import { HttpException, HttpStatus, Injectable } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { Like, Repository } from 'typeorm'
import { CreateUserDto } from './dto/create-user.dto'
import { UpdateUserDto } from './dto/update-user.dto'
import { User } from './entities/user.entity'
import { Role } from 'src/role/enum'
import { LoginBody } from './dto/login-user.dto'
import { CustomRequest } from 'src/type'
import { getMenu } from 'src/menu'
import { Subject } from 'src/subject/entities/subject.entity'
import * as bcrypt from 'bcryptjs'
import * as CryptoJS from 'crypto-js'
import { ExamSubject } from 'src/exam/entities/exam_subject.entity'

// @Injectable()：将 UserService 类标记为可注入的服务提供者，使其可以在控制器中通过依赖注入的方式使用。
@Injectable()
export class UserService {
  constructor(
    // 构造函数中使用 @InjectRepository 装饰器将 User 和 Subject 实体的存储库注入到服务类中，
    // 分别存储在 user 和 subject 属性中，用于对用户表和科目表进行数据库操作。
    @InjectRepository(User) private readonly user: Repository<User>,
    @InjectRepository(Subject) private readonly subject: Repository<Subject>,
    @InjectRepository(ExamSubject) private readonly exam_subject: Repository<ExamSubject>
  ) {}

  // 登录
  async login(body: LoginBody, req: CustomRequest) {
    const user_info = await this.user.findOne({ where: { phone: body.phone } })

    console.log(body.password)
    console.log(user_info.password)

    // 进行解密
    const bytes = CryptoJS.AES.decrypt(body.password, 'yujian')
    const decryptedPassword = bytes.toString(CryptoJS.enc.Utf8)

    // 和数据的密码进行检验
    const password_res = await bcrypt.compare(decryptedPassword, user_info.password)

    // 密码一致
    if (password_res) {
      const user_data = await this.user.findOne({ where: { phone: body.phone } })
      req.session.login = 1
      req.session.phone = body.phone
      req.session.user_id = user_data._id
      req.session.role = user_data.role

      console.log('写入session成功', req.session)
      // 最后返回用户信息给前端
      const new_user_info = await this.user.findOne({ where: { phone: body.phone } })
      new_user_info.password = ''

      return new_user_info
    } else {
      throw new HttpException('登录错误', HttpStatus.UNAUTHORIZED)
    }
  }

  // 注册
  async register(body: LoginBody, req: CustomRequest) {
    const user_data = await this.user.findOne({ where: { phone: body.phone } })

    // 如果已经注册
    if (user_data) {
      req.session.login = 1
      req.session.phone = body.phone
      req.session.user_id = user_data._id
      req.session.role = user_data.role
    } else {
      // 解密
      const bytes = CryptoJS.AES.decrypt(body.password, 'yujian')
      const decryptedPassword = bytes.toString(CryptoJS.enc.Utf8)

      const hashedPassword = await bcrypt.hash(decryptedPassword, 10)
      // 创建用户信息并设置session信息
      const newUser = this.user.create({ phone: body.phone, password: hashedPassword, role: Role.student })
      await this.user.save(newUser)

      // 设置session信息
      req.session.login = 1
      req.session.phone = body.phone
      req.session.user_id = newUser._id
      req.session.role = newUser.role
    }

    console.log('写入session成功', req.session)
    // 最后返回用户信息给前端
    const new_user_info = await this.user.findOne({ where: { phone: body.phone } })
    new_user_info.password = ''

    return new_user_info
  }

  // 修改密码
  async updatePassword(body, req) {
    const user_info = await this.user.findOne({ where: { _id: req.session.user_id } })

    // 对旧密码进行解密
    const old_bytes = CryptoJS.AES.decrypt(body.old_password, 'yujian')
    const old_decryptedPassword = old_bytes.toString(CryptoJS.enc.Utf8)

    // 和数据的密码进行检验
    const password_res = await bcrypt.compare(old_decryptedPassword, user_info.password)

    // 密码一致
    if (password_res) {
      // 对新密码进行解密
      const new_bytes = CryptoJS.AES.decrypt(body.new_password, 'yujian')
      const new_decryptedPassword = new_bytes.toString(CryptoJS.enc.Utf8)

      const hashedPassword = await bcrypt.hash(new_decryptedPassword, 10)

      await this.user.update({ _id: user_info._id }, { password: hashedPassword })

      return {
        code: 200,
        data: '修改密码成功'
      }
    } else {
      return {
        code: 400,
        data: '密码错误'
      }
    }
  }

  // 退出
  logout(req: CustomRequest) {
    req.session.login = null
    req.session.phone = null
    req.session.user_id = null
    req.session.role = null

    return {
      session: req.session
    }
  }

  // 注册或者修改个人信息 或者是 学员管理的课程权限编辑
  async update(id: number, updateUserDto: UpdateUserDto, req: CustomRequest) {
    // id是修改课程权限的那位学员的user_id
    // 学员管理的课程权限编辑
    if (updateUserDto.subject_role) {
      // 用到了事务，因为涉及到了两张表
      this.user.manager.transaction(async manager => {
        // User：指定要查找的实体类型，即 User 实体。
        // relations: ['subject']：表示在查询用户信息时，同时关联查询用户的 subject 关系。这意味着查询结果中会包含用户关联的科目信息。
        const user_data = await manager.findOne(User, { relations: ['subject'], where: { _id: Number(id) } })

        const subject_role = updateUserDto.subject_role
        const subjectList = []
        console.log(`课程权限 =============》${subject_role}`)

        // 如果是数组
        if (Array.isArray(subject_role)) {
          // 从subject表中一个一个找
          subject_role.forEach(async item => {
            const subject = await manager.findOne(Subject, { where: { _id: Number(item) } })
            subjectList.push(subject)
          })
        } else {
          // 如果是单个值
          const subject = await manager.findOne(Subject, { where: { _id: Number(subject_role) } })
          subjectList.push(subject)
        }

        // 然后在对应的user上添加
        user_data.subject = subjectList as Subject[]
        await manager.save(User, user_data)
      })
      return '修改课程权限成功'
    } else {
      // 注册或者修改个人信息
      const res = await this.user.update({ _id: id }, { ...updateUserDto, has_person_info: true })
      // res.affected：表示更新操作影响的记录数。如果 res.affected 等于 1，说明成功更新了一条记录
      if (res.affected == 1) {
        // ？？？？可能要修改
        const user_data = await this.user.findOne({ where: { _id: id } })
        // console.log(`11111111111${user_data}`)
        req.session.role = user_data.role
        return '修改成功'
      } else {
        throw new HttpException('修改失败', HttpStatus.FORBIDDEN)
      }
    }
  }

  // 获取用户信息
  async findUser(req: CustomRequest) {
    const user_id = req.session.user_id
    // 会进行多表查询
    const user_data = await this.user.findOne({ relations: ['subject'], where: { _id: user_id } })
    const subject_role = user_data.subject
    // 在用户信息上添加subject
    // 比如：subject: [2]
    user_data.subject = subject_role.map(item => item._id) as any

    return user_data
  }

  // 查找菜单
  findMenu(req: CustomRequest) {
    const role = req.session.role as keyof typeof Role
    return getMenu(role)
  }

  // 获取学生列表
  async getStudent(query) {
    // relations: ['subject']：指定在查询学生信息时，同时关联查询该学生对应的 subject （科目）信息，即进行多表查询。
    // relations: ['subject']：此配置是触发多表查询的关键。它告知 TypeORM 在查询 User 实体时，同时关联查询 User 对应的 subject 信息。
    const student_list = await this.user.find({ relations: ['subject'], where: { role: Role.student, name: Like(`%${query.name}%`), phone: Like(`%${query.phone}%`) }, skip: (query.pageNo - 1) * query.pageSize, take: query.pageSize })

    const total = await this.user.count({ where: { role: Role.student, name: Like(`%${query.name}%`), phone: Like(`%${query.phone}%`) } })
    // 将subject(二级课程权限)改成id
    const handle_student_list = student_list.map(stu_item => {
      return {
        ...stu_item,
        subject: stu_item.subject.map(item => item._id)
      }
    })

    return { count: total, data: [...handle_student_list] }
  }

  // 删除学生
  async removeStudent(id: number) {
    await this.user.delete(id)
    return `删除学生成功`
  }

  // 获取管理员列表
  async getAdmin(query) {
    // take 用于指定查询时获取的记录数量
    const data = await this.user.find({ where: { role: 'admin', name: Like(`%${query.name}%`), phone: Like(`%${query.phone}%`) }, skip: (query.pageNo - 1) * query.pageSize, take: query.pageSize })
    const count = await this.user.count({ where: { role: 'admin', name: Like(`%${query.name}%`), phone: Like(`%${query.phone}%`) } })
    return { data, count }
  }

  // 新增管理员
  async addAdmin(createUserDto: CreateUserDto) {
    const admin_data = { ...createUserDto, role: 'admin' }
    const admin = await this.user.create(admin_data)
    await this.user.save(admin)

    return '新增管理员成功'
  }

  // 删除老师
  async removeAdmin(id: number) {
    await this.user.delete(id)
    return `删除老师成功`
  }

  // 获取各职位的数量
  async getRole() {
    const teacher = await this.user.find({ where: { role: Role.admin } })
    const student = await this.user.find({ where: { role: Role.student } })
    const super_admin = await this.user.find({ where: { role: Role.super_admin } })

    return {
      teacher: teacher.length,
      student: student.length,
      super_admin: super_admin.length
    }
  }

  // 获取各种教育水平的数量
  async getEdu() {
    const junior_high_school = await this.user.find({ where: { edu: '初中' } })
    const senior_high_school = await this.user.find({ where: { edu: '高中' } })
    const junior_college = await this.user.find({ where: { edu: '大专' } })
    const adult_undergraduate = await this.user.find({ where: { edu: '成人本科' } })
    const junior_college_to_undergraduate = await this.user.find({ where: { edu: '专升本' } })
    const second_tier_undergraduate = await this.user.find({ where: { edu: '二本' } })
    const first_tier_undergraduate = await this.user.find({ where: { edu: '一本' } })
    const postgraduate = await this.user.find({ where: { edu: '研究生' } })

    return {
      junior_high_school: junior_high_school.length,
      senior_high_school: senior_high_school.length,
      junior_college: junior_college.length,
      adult_undergraduate: adult_undergraduate.length,
      junior_college_to_undergraduate: junior_college_to_undergraduate.length,
      second_tier_undergraduate: second_tier_undergraduate.length,
      first_tier_undergraduate: first_tier_undergraduate.length,
      postgraduate: postgraduate.length
    }
  }

  // 获取各种技术栈的数量
  async getTechStack() {
    const query = this.user.createQueryBuilder('user').select('user.techStack', 'name').addSelect('COUNT(user._id)', 'value').groupBy('user.techStack')
    const result = await query.getRawMany()
    return result.map(({ name, value }) => ({ value: parseInt(value, 10), name }))
  }

  // 查看试卷是否被批阅的数量
  async getCorrect() {
    const correct_true = await this.exam_subject.find({ where: { judge: true } })
    console.log(correct_true)
    const correct_false = await this.exam_subject.find({ where: { judge: false } })
    return {
      correct_true: correct_true.length,
      correct_false: correct_false.length
    }
  }
}
